<?php
namespace App\Services\Algo;
/**
 * 测评算法基类
 * User: admin
 * Date: 2016/11/24
 * Time: 15:52
 */

use App\Models\LogHelper;
use EasyWeChat\Support\Log;

class BaseTestingAlgo{
    protected $tid;

    protected $answerStr;

    protected $answers;

    public function __construct($tid,$answerStr)
    {
        $this->tid = $tid;

        $this->answerStr = $answerStr;

       $this->answers = $this->convertAnswer($this->answerStr);
    }

    /**将answer转换为数组
     * @param $answerStr
     * @return array
     */
    protected function convertAnswer($answerStr){
        $answers = [];
        $answerArr = explode('##',$answerStr);
        if(count($answerArr)>0){
            foreach ($answerArr as $answer){
                $singleArr = explode(':',$answer);
                if(count($singleArr)>0){
                    $obj['index'] = $singleArr[0];
                    $obj['weight'] = $this->formateWeight($singleArr[1]);
                    $obj['answer'] = $singleArr[2];
                    array_push($answers,$obj);
                }
            }
        }
        return $answers;
    }

    /**多选题格式化权重
     * @param $str 提交权重字符串
     * @return number
     */
    protected function formateWeight($str){
        $arr = explode("|||",$str);
        $sum = array_sum($arr);
        return (string)$sum;
    }

    /**第四中类型（10000,*,$4,/,$3,/,$3）解析成题号，权重，答案数组
     * @param array $typeFourExpress 二维数组array ['index']['weight']['answer']
     * @param $answers
     * @return array
     */
    public function fourTypeArray($typeFourExpress,$answers){
        $arr = [];
        $fourTypeRes = [];
        if(!empty($typeFourExpress)){
            foreach($typeFourExpress as $k => $v){
                    $arr = $this->formateExpress($answers,$v);
                    array_push($fourTypeRes, $arr);
            }
        }
        return $fourTypeRes;
    }

    //格式化计算式循环
    protected function formateExpress($answers,$typeFourExpress){
        $typeFourExpress['index'] =(string)$typeFourExpress['index'] ;
        $typeFourExpress['weight']=(string)$this ->fourcalculate($answers,$typeFourExpress['relateExpress']);
        $typeFourExpress['answer']='0';
        unset($typeFourExpress['relateExpress']);
        return $typeFourExpress;
    }

    //根据计算式计算
    protected function fourcalculate($answers,$parstr)
    {
        if (preg_match($expStr = '/^sum\(@(\d+)~@(\d+)\)/', $parstr, $matches)) {
            if ($matches > 2) {
                $start = $matches[1];
                $end = $matches[2];
                $sum = 0;
                for ($i = $start; $i <= $end; $i++) {
                    $sum += $this->getValue($answers, $i, 'weight');
                }
                $str = preg_replace($expStr, $sum, $parstr);
                return round(eval("return $str;"), 0);
            }
        } else if (preg_match($expStr = '/^sum\($(\d+)~$(\d+)\)/', $parstr, $matches)) {
            if ($matches > 2) {
                $start = $matches[1];
                $end = $matches[2];
                $sum = 0;
                for ($i = $start; $i <= $end; $i++) {
                    $sum += $this->getValue($answers, $i, 'value');
                }
                $str = preg_replace($expStr, $sum, $parstr);
                return round(eval("return $str;"), 0);
            }
        } else {
            $cal_arr = explode(',', $parstr);
            $cal_replace = $this->paramterReplace($answers, $cal_arr);
            $str = implode('', $cal_replace);
            $result = eval("return $str;");
            return $result;
        }
    }

    /**根据题号替换值
     * @param $answers
     * @param $arr
     */
    protected function paramterReplace($answers,$arr){
        foreach($arr as $k => $v){
            if(substr($v,0,1) == '$'){ //获取值并替换
                $index = (int)substr($v,1);
               $answer = $this->getValue($answers,$index,'answer');
                $arr[$k]=$answer;
            }elseif(substr($v,0,1) == '@'){//获取权重并替换
                $index = (int)substr($v,1);
                $weight = $this->getValue($answers,$index,'weight');
                $arr[$k]=$weight;
            }elseif(substr($v,0,1) == '%'){

            }
        }
        return $arr;
    }

    /**根据题号获取相应的权重或者值
     * @param $answers
     * @param $index
     * @param $valueType
     * @return null
     */
    protected function getValue($answers,$index,$valueType){
        $value = null;
        foreach($answers as $k => $v){
            if($v['index'] == $index){
               $value = $answers[$k][$valueType];
            }
        }
        return $value;
    }


    /**
     * 根据题号获取answer对象
     * @param $index
     * @return array $obj
     */
    public function getAnswerObjByIndex($index,$answers = null){
        $answers = $answers ? $answers : $this->answers;
        $obj = [];
        foreach ($answers as $answer){
            if($index == $answer['index']){
                $obj = $answer;
                break;
            }
        }
        return $obj;
    }


    public function getAnswerTotalScore($answers){
        $totalScore =0;
        foreach ($answers as $answer){
            $totalScore = $totalScore + $answer['weight'];
        }
        return $totalScore;
    }



    /**根据题号数组获取对应权重或值数组
     * @param $arr 题号一维数组
     * @param $answers  答案二位数组
     * @param $value  answer或者weight
     * @return array   题号对应权重数组
     */
    protected function getValuearray($arr, $answers, $value)
    {
        $weghtarray = [];
        foreach ($answers as $key => $val) {
            if (in_array($val['index'],$arr)) {
                array_push($weghtarray, $val[$value]);
            }
        }
        return $weghtarray;
    }

    /**将答案数组还原为字符串
     * @param $arrAnswers
     * @return string
     */
    public function arrToStr($arrAnswers){
            $arr = [];
            foreach($arrAnswers as $k => $v){
                $arr[0]=$v['index'];
                $arr[1]=$v['weight'];
                $arr[2]=$v['answer'];
                $str=implode(":",$arr);
                $answers[$k]=$str;
            }
            $answerStr = implode("##",$answers);
            return $answerStr;
    }


    /**
     * 计算第六种类型的权值
     */
    protected function getTypeSixSingleItemWeight($expressStr){
        $expressionList = $this->convertTypeSixExpression($expressStr);
        $weight = 0;
        foreach ($expressionList as $exp){
            $answerObj = $this->getAnswerObjByIndex($exp['index'],$this->answers);
            $replaceStr = '';
            switch ($exp['operate']){
                case '@':
                    $replaceStr = $answerObj['weight'];
                    break;
                case '$':
                    $replaceStr = $answerObj['answer'];
                    break;
            }
            $search = $exp['operate'].$exp['index'];
            //首先替换表达式  $val=0<@23&&@23<4?1:0 中的@23，
            //同时下面的$val变量一定要与表达式中的$val保持一致，否则$val条件判断值取不到结果。
            $val = str_replace($search,$replaceStr,$exp['condition']);
            //通过php的eval函数计算php的表达式
            eval($val);
            if($val){
                //如果条件表达式条件成立则去权重。
                $weight = $exp['weight'];
                break;
            }
        }
        return $weight;
    }

    /**
     * 转换第六种类型的表达式为list
     *  0<=$4&&$4<80:$4##0
    80<=$4&&$4<85:$4##2
    85<=$4&&$4<300:$4##3
     **/
    protected function convertTypeSixExpression($expressionStr){
        $arr = [];
        $expressions = explode("|||",$expressionStr);
        if(count($expressions)>0){
            foreach ($expressions as $e){
                if(!$e){
                    continue;
                }
                $data = explode('##',$e);
                $relateExp = $data[0];
                // 解析这种形式的表达式0<=$4&&$4<80:$4
                $condArr = explode(':',$relateExp);
                //如果不存在则构造一个
                $condition = $this->compactConditionStr($condArr[0]);
                $obj['condition'] = $condition;
                //拆分条件表达式中的所以和操作符号($和@)
                if($operateObj = $this->compactTypeSixOperateStr($condArr[1])){
                    foreach ($operateObj as $key => $val){
                        $obj[$key] = $val;
                    }
                }else{
                    $obj['index'] = -1;
                    $obj['operate'] = '';
                }
                $obj['weight'] = $data[1];
                array_push($arr,$obj);
            }
        }
        return $arr;
    }

    /**
     * 组装条件判断表达是表达式 形如《10<@23<=20这种
     * @param string $operateStr
     * @return array
     */
    protected function compactConditionStr($condition){
        //如果不存在则构建一个假的条件表达式
        $condition = $condition ? $condition : '1==0';
        //注意此处是php中的表达式，一定要带上分号，否则会出错。
        $condition = '$val='.$condition.'?1:0;';
        return $condition;
    }

    /**
     * 拆分操作表达式 形如@23或者$23这种
     * @param string $operateStr
     * @return array
     */
    protected function compactTypeSixOperateStr($operateStr){
        $obj = [];
        $operateArr = ['@','$'];
        $firstLetter = substr($operateStr,0,1);
        if(in_array($firstLetter,$operateArr)){
            $obj['operate'] = $firstLetter ;
            $obj['index'] = (int)substr($operateStr,1);
        }
        return $obj;
    }
}